package com.myframework.utils.dbutil;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.*;
import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;

import com.myframework.utils.stringutil.StringUtil;

public class SecureDataSourceFactory extends BasicDataSourceFactory {

	public SecureDataSourceFactory() {
	}

	@SuppressWarnings("rawtypes")
	public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
		if (obj instanceof Reference) {
			setUsername((Reference) obj);
			setPassword((Reference) obj);
			setUrl((Reference) obj);
		}
		return super.getObjectInstance(obj, name, nameCtx, environment);
	}

	private void setUsername(Reference ref) throws Exception {
		findDecryptAndReplace("username", ref);
	}

	private void setPassword(Reference ref) throws Exception {
		findDecryptAndReplace("password", ref);
	}

	private void setUrl(Reference ref) throws Exception {
		findDecryptAndReplace("url", ref, true);
	}

	private void findDecryptAndReplace(String refType, Reference ref) throws Exception {
		findDecryptAndReplace(refType, ref, false);
	}

	private void findDecryptAndReplace(String refType, Reference ref, boolean isSubString) throws Exception {
		int idx = find(refType, ref);
		if (idx != -1) {
			String decrypted = decrypt(idx, ref, isSubString);
			replace(idx, refType, decrypted, ref);
		}
	}

	private void replace(int idx, String refType, String newValue, Reference ref) throws Exception {
		ref.remove(idx);
		ref.add(idx, new StringRefAddr(refType, newValue));
	}

	private String decrypt(int idx, Reference ref, boolean isSubString) throws Exception {
		String cipher = ref.get(idx).getContent().toString();
		if (isSubString) {
			if (!StringUtil.isEmpty(cipher)) {
				String match = "user=";
				if (cipher.contains(match)) {
					String cuser = "";
					cuser = cipher.substring(cipher.indexOf(match) + match.length());
					cuser = cuser.substring(0, cuser.indexOf(";"));
					cipher = cipher.replace(cuser, EncryptionUtil.decrypt(cuser));
				}
				match = "password=";
				if (cipher.contains(match)) {
					String cpass = "";
					cpass = cipher.substring(cipher.indexOf(match) + match.length());
					cpass = cpass.substring(0, cpass.indexOf(";"));
					cipher = cipher.replace(cpass, EncryptionUtil.decrypt(cpass));
				}

				return cipher;
			}
		}
		if (!StringUtil.isEmpty(cipher))
			return EncryptionUtil.decrypt(cipher);
		else
			return cipher;
	}

	private int find(String addrType, Reference ref) throws Exception {
		Enumeration<RefAddr> enu = ref.getAll();
		for (int i = 0; enu.hasMoreElements(); i++) {
			RefAddr addr = (RefAddr) enu.nextElement();
			if (addr.getType().compareTo(addrType) == 0)
				return i;
		}

		return -1;
	}

}
